
#ifndef  __KC_FEKCAB_FILE_CELL_HPP_2010__
#define  __KC_FEKCAB_FILE_CELL_HPP_2010__

#include <string>
#include <fstream>

#include "bocat/common/lrucache.hpp"

#include "timestamp.hpp"
#include "recloc.hpp"
#include "record.hpp"
#include "indexiter.hpp"


namespace   fekcab   {

class   FileCell
{

public	:
	static const std::string	OP_PUT;
	static const std::string	OP_GET;
	static const std::string	OP_DEL;

public	:
	FileCell( const std::string data_dir, u_int32_t file_rotate_size=0, int32_t slim = 0 );
	~FileCell();

public  :
    int put( const std::string& skey_b64,
             const std::string& kpin_b64,
             const std::string& key,
             const std::string& data,
			 Timestamp&			ts,
             RecordLocation&    loc,
			 const RecordLocation& prev_loc );

    int get( const std::string& skey_b64,
             const std::string& kpin_b64,
             const std::string& key,
                   std::string& data,
			 Timestamp&			ts,
             const RecordLocation&  loc,
			       RecordLocation& prev_loc );

    int erase( const std::string&   skey_b64,
               const std::string&   kpin_b64,
               const std::string&   key,
			   const   Timestamp&	ts,
               const RecordLocation&    loc );

public	:
	int	put( std::vector< Record >& record_v, Timestamp& ts );
	int	append( std::vector< Record >& record_v, Timestamp& ts );
	int	erase( std::vector< Record >& record_v, Timestamp& ts );

public	:
	IndexIterator*	getSlimIndexIterator( void );
	void		freeSlimIndexIterator( IndexIterator*, bool done=true );
	std::string		getSlimmingFile( void ) const { return _file_slimming; }
	int				getSlimmingFileNo( void ) const { return _fileno_slimming; }

private	:
	void	initialize();
	void	finalize();

	void	scanDataDirectory( void );

	int		getFileToSlim( std::string& file_to_slim );
	int		getFileNoFromName(const std::string&);


	std::string		getNextAppendFileName( void );
	std::string		getCurrentAppendFileName( void );
	std::string		getAppendFileName( void );
	std::string		getDeleteFileName( void );
	std::string		getFileName( u_int32_t fileno );
	std::string		getReadFileName( u_int32_t fileno );

	std::ofstream&	openAppendFile( void );
	std::ofstream&	openDeleteFile( void );
	std::ifstream&	openReadFile( u_int32_t fileno );
	void			closeAllReadFiles( void );
	
	char*	getBuf( u_int32_t buf_size );

private	:
	std::string	_data_dir;

	u_int32_t	_file_rotate_size;
	int32_t		_slim;

private	:
	int32_t		_slim_lowater;
	bool		_slimming;

	int			countFileToSlim( void );


private :
	std::ofstream	_ofs_append;
	std::ofstream	_ofs_delete;

	u_int32_t	_min_fileno;
	u_int32_t	_max_fileno;

	static const std::string	SLICE_BASENAME;
	static const std::string	DELETE_FILENAME;
	static const u_int32_t		MIN_SLICE_SIZE_THRESHOLD;
	static const u_int32_t		MAX_SLICE_SIZE_THRESHOLD;

	// cache for read only file handles
	typedef	std::ifstream*	ifsp_type;
	typedef	bocat::common::LRUCache< u_int32_t, ifsp_type >	ifsp_cache_type;

	ifsp_cache_type	_ifsp_cache;
	boost::mutex	_ifsp_cache_mutex;

	IndexIterator*	_index_iterator_p;
	boost::mutex	_index_iterator_mutex;
	std::string		_file_slimming;
	int				_fileno_slimming;

	char*		_buf_p;
	u_int32_t	_buf_size;

	std::string		_dummy_loc_b64;
};  //// class FileCell

}   ////    namespace   fekcab

#endif  ////    __KC_FEKCAB_FILE_CELL_HPP_2010__

